package com.wehealth.three.lib_connect.device.usbdevice.data;


import android.widget.Toast;

import com.wehealth.three.lib_connect.utils.PreferenceUtils;


/***
 * 通过设备采集到的原始的心电数据的解析工作
 */
public class ParseOriginEcgData {
    public static final String TAG = "EcgDataParser";
    //数据包的最大长度
    public static final int MAX_PACKET_LEN = 100;
    //导联通道数
    public static final int LEAD_NUM = 12;
    //包数据的开始
    public static final byte PACKET_HEAD = (byte) 0xA5;
    //包数据的结束
    public static final byte PACKET_TAIL = 0x5A;
    //包数据的长度
    public static final int PACK_DATA_LEN = 31;
    //获取设备基础信息的数据解析
    public static final int CMD_MODEL = 0;
    //获取心电数据信息的数据解析
    public static final int DATA_MODEL = 1;
    //存储获取数据的缓存数组
    private byte buffer[];
    //包中数据个数
    private short dataNum;
    //获取包头标志
    private boolean packTop;

    EcgDataGetListener ecgListener;
    //数据解析模式
    private int dataModel;

    public ParseOriginEcgData(EcgDataGetListener ecgListener) {
        buffer = new byte[MAX_PACKET_LEN];
        dataNum = 0;
        packTop = false;
        this.ecgListener = ecgListener;
        dataModel = CMD_MODEL;
    }

    public void ecgDataParserInit() {
        dataNum = 0;
        packTop = false;
    }

    /****
     * 读取设备信息的时候，手机端向设备端发送的消息
     * @return
     */
    public static byte[] packEcgDeviceInfoCmd() {
        byte[] buffer;
        buffer = new byte[5];
        buffer[0] = PACKET_HEAD;
        buffer[1] = 0x06;
        buffer[2] = 0x00;
        buffer[3] = 0x06;
        buffer[4] = PACKET_TAIL;
        return buffer;
    }

    /***
     * 开始采集
     * @return
     */
    public static byte[] packEcgDeviceStart() {
        byte[] cmdBuf;

        cmdBuf = new byte[5];
        cmdBuf[0] = PACKET_HEAD;
        cmdBuf[1] = 0x03;
        cmdBuf[2] = 0x00;
        cmdBuf[3] = 0x03;
        cmdBuf[4] = PACKET_TAIL;

        return cmdBuf;
    }

    /***
     * 停止采集
     * @return
     */
    public static byte[] packEcgDeviceStop() {
        byte[] cmdBuf;
        cmdBuf = new byte[5];
        cmdBuf[0] = PACKET_HEAD;
        cmdBuf[1] = 0x04;
        cmdBuf[2] = 0x00;
        cmdBuf[3] = 0x04;
        cmdBuf[4] = PACKET_TAIL;

        return cmdBuf;
    }

    /***
     * 获取设备校验信息
     * @return
     */
    public static byte[] packEcgDeviceCheck() {
        byte[] cmdBuf;
        cmdBuf = new byte[6];
        cmdBuf[0] = PACKET_HEAD;
        cmdBuf[1] = 0x07;
        cmdBuf[2] = 0x01;
        cmdBuf[3] = 0x00;
        cmdBuf[4] = 0x06;
        cmdBuf[5] = PACKET_TAIL;

        return cmdBuf;
    }


    /****
     * 解析数据
     * @param EcgData
     * @param dLen
     */
    public void ecgParserPacket(byte[] EcgData, int dLen) {
        int i = 0;
        byte[] pData;
        pData = EcgData;
        //根据模式的不同对数据进行解析
        for (i = 0; i < dLen; i++) {
            //不同模式对数据的解析方式是不同的
            if (dataModel == CMD_MODEL) {
                parserEcgCmd(pData[i]);
            } else {
                parserEcgData(pData[i]);
            }
            //控制一次只解析100个字节的数据
            if (dataNum >= MAX_PACKET_LEN) {
                packTop = false;
                dataNum = 0;
            }
        }
    }




    /****
     *  获取基础信息的数据的解析（不是心电数据的解析）
     *  一个字节的数据的解析
     * @param data
     * @return
     */
    private boolean parserEcgCmd(byte data) {
        boolean cmdInFos = false;
        //// 帧头的处理
        if (!packTop) {
            if (PACKET_HEAD == data) {
                dataNum = 0;
                packTop = true; // 包头标志
            }
            //真实数据的解析
        } else {
            //判断是否到帧尾 帧尾开始解析数据
            if (PACKET_TAIL == data) {
                if (EcgXORCheck(buffer, dataNum)) {
                    cmdInFos = ecgPacketCmdData(buffer, dataNum);
                }
                packTop = false;
                //不是帧尾将数据添加到缓存数组
            } else {
                buffer[dataNum++] = data;
                if (dataNum >= 100) {
                    packTop = false;
                    dataNum = 0;
                }
            }
        }
        return cmdInFos;
    }

    /***
     * 通过异或操作对状态进行检查
     * @param buffer
     * @param size
     * @return
     */
    private boolean EcgXORCheck(byte[] buffer, int size) {
        byte cksum = 0;
        int i;
        //获取当前数据的长度
        int len = buffer[1];
        //如果数据长度大于实际的长度
        if (len > (size - 2))
            return false;
        //对所有的数据做异或操作
        for (i = 0; i < (size - 1); i++)
            cksum ^= buffer[i];
        //？没懂
        return (cksum == buffer[i]);
    }

    /***
     * 校验通过了真实的数据解析过程
     * @param buffer
     * @param size
     * @return
     */
    private synchronized boolean ecgPacketCmdData(byte[] buffer, int size) {
        if (buffer[0] == 0x06) {
            byte[] tmp = new byte[17];
            for (int i = 0; i < 17; i++) {
                tmp[i] = (byte) (buffer[i + 6] ^ 0x11);
            }
            String serialNo = new String(tmp);
            PreferenceUtils.getInstance().setTempSerialNo(serialNo);
            dataModel = DATA_MODEL;
            dataNum = 0;
            packTop = false;
            return true;
        }
        return false;
    }


    /***
     * 修改数据传输模式
     */
    public void setModel() {
        dataModel = DATA_MODEL;
        dataNum = 0;
        packTop = false;
    }

    /***
     * 心电数据的解析
     * @param data
     */
    private void parserEcgData(byte data) {
        if (!packTop) {
            // 找帧头  data<0?
            if (data < 0) {
                dataNum = 0;
                packTop = true; // 包头标志
                buffer[dataNum++] = data;
            }
        } else {
            if (data >= 0) {
                if (dataNum >= (PACK_DATA_LEN - 1)) {
                    buffer[dataNum] = data;
                    ecgPacketEcgData(buffer, PACK_DATA_LEN);
                    packTop = false;
                    dataNum = 0;
                } else {
                    buffer[dataNum++] = data;
                }

            } else {
                packTop = false;
                dataNum = 0;
            }
        }
    }

    /***
     * 心电数据的解析工作
     * @param buffer
     * @param size
     */
    private synchronized void ecgPacketEcgData(byte[] buffer, int size) {
        boolean[] bitData;
        byte[] packetEcgData;
        byte[] leadData;
        int[] ecgData;
        int[] ecgDataReal;
        boolean[] leadState;
        boolean pace;
        int packageId;
        ecgData = new int[8];
        //获取的是导联的连接状态
        leadState = new boolean[9];
        packetEcgData = new byte[24];
        leadData = new byte[3];
        bitData = new boolean[PACK_DATA_LEN - 4];
        ecgDataReal = new int[12];
        getEcgDataBitValue(buffer, size, bitData);
        getLeadStateOriginalData(buffer, size, bitData, leadData);
        packageId = leadData[0];
        getLeadEcgOriginalData(buffer, size, bitData, packetEcgData);
        pace = getEcgPaceData(leadData);
        getEcgLeadValue(leadData, leadState);
        getEcgDataValue(packetEcgData, ecgData);
        for (int i = 0; i < 8; i++) {
            if (ecgData[i] > 0x800000)
                ecgData[i] -= 0x1000000;
        }
        ecgDataReal[0] = ecgData[0];
        ecgDataReal[1] = ecgData[1];
        ecgDataReal[2] = ecgData[1] - ecgData[0]; // III II - I
        ecgDataReal[3] = -((ecgData[1] + ecgData[0]) >> 1); // avR
        ecgDataReal[4] = ecgData[0] - (ecgData[1] >> 1); // avL
        ecgDataReal[5] = ecgData[1] - (ecgData[0] >> 1); // avF
        for (int i = 2; i < 8; i++)
            ecgDataReal[i + 4] = ecgData[i];

        ecgListener.getOriginalEcgData(ecgDataReal, LEAD_NUM, leadState, pace, packageId);
    }

    /***
     * 获取前四个字节中的对应的bit数据
     * @param buffer
     * @param size
     * @param bitData
     */
    private void getEcgDataBitValue(byte[] buffer, int size, boolean[] bitData) {
        int cnt = 0;
        int i, j;
        int bitNum;
        for (j = 0; j < 4; j++) {
            if (j == 0) {
                //第一个字节中的有效数据是6个 0循环到5
                bitNum = 5;
            } else {
                //2到4字节中的有效数据为7个 0循环到6
                bitNum = 6;
            }
            for (i = bitNum; i >= 0; i--) {
                if ((buffer[j] & (1 << i)) == 0) {
                    bitData[cnt++] = false;
                } else {
                    bitData[cnt++] = true;
                }
            }
        }
    }

    /***
     * 获取存储导联状态的3个字节的数据
     * @param buffer
     * @param size
     * @param bitData
     * @param leadData
     */
    private void getLeadStateOriginalData(byte[] buffer, int size, boolean[] bitData, byte[] leadData) {
        int i;
        for (i = 0; i < 3; i++) {
            if (bitData[i]) {
                //将采集到的数据同 128进行按位或的操作
                leadData[i] = (byte) (buffer[i + 4] | 0x80);
            } else {
                //直接去数据
                leadData[i] = buffer[i + 4];
            }
        }
    }

    /****
     * 获取存储心电数据的24字节
     * @param buffer
     * @param size
     * @param bitData
     * @param ecgData
     */
    private void getLeadEcgOriginalData(byte[] buffer, int size, boolean[] bitData, byte[] ecgData) {
        int i;
        for (i = 0; i < 24; i++) {
            if (bitData[i + 3]) {
                ecgData[i] = (byte) (buffer[i + 7] | 0x80);
            } else {
                ecgData[i] = buffer[i + 7];
            }
        }
    }

    /***
     *  解析起搏数据的方式已清楚
     * 获取是否开启起搏的标志
     * @param leadData
     * @return
     */
    private boolean getEcgPaceData(byte[] leadData) {
        boolean state = false;
        //获取心电数据的第三个字节 之后按位与去最后一位
        if ((leadData[2] & 0x01) == 1)
            state = true;
        return state;
    }

    /**
     * 解析导联状态的方式已清楚
     * 解析三个字节的导联状态数据获取导联状态
     *
     * @param leadData
     * @param leadState
     */
    private void getEcgLeadValue(byte[] leadData, boolean[] leadState) {
        int cnt = 0;
        //此处的循环0到1是因为 只有第2个字节和第3个字节有数据
        for (int i = 0; i < 2; i++)
            for (int j = 0; j < (5 - i); j++) {
                //取第二个字节 通过按位与取对应的位
                if ((leadData[i + 1] & (1 << (i * 4 + j))) == 0) {
                    leadState[cnt++] = false;
                } else {
                    leadState[cnt++] = true;
                }
            }
    }

    /***
     * 解析字节获取心电数据
     * @param data
     * @param ecgData
     */
    private void getEcgDataValue(byte[] data, int[] ecgData) {
        int cnt = 0;
        int j = 0;
        byte[] tmp;
        tmp = new byte[3];
        for (int i = 0; i < 24; i++) {
            tmp[j++] = data[i];
            if (j >= 3) {
                ecgData[cnt++] = toInt(tmp);
                j = 0;
            }
        }
    }

    private int toInt(byte[] bytes) {
        switch (bytes.length) {
            case 1:
                return 0xff & bytes[0];
            case 2:
                return ((bytes[0] << 8) & 0xff00) + (bytes[1] & 0xff);
            case 3:
                return ((bytes[0] << 16) & 0xff0000) + ((bytes[1] << 8) & 0xff00)
                        + (bytes[2] & 0xff);
            default:
                return ((bytes[0] << 24) & 0xff000000)
                        + ((bytes[1] << 16) & 0xff0000)
                        + ((bytes[2] << 8) & 0xff00) + (bytes[3] & 0xff);
        }
    }

    // 接收心电数据
    public interface EcgDataGetListener { /* 使用接口实现回调 */
        void getOriginalEcgData(int data[], int len, boolean[] leadState, boolean pace, int packageId);
    }


    public void stopInit() {
        dataModel = CMD_MODEL;
        dataNum = 0;
        packTop = false;
    }

    public boolean EcgParserCMDInfo(byte[] cmd) {
        boolean cmdInfo = false;
        for (byte b : cmd) {
            cmdInfo = parserEcgCmd(b);
            if (cmdInfo) {
                break;
            }
        }
        return cmdInfo;
    }
}
